package com.adee.java;

import com.adee.java.classloader.Person;

import java.lang.reflect.InvocationTargetException;

/* 泛型
 *  https://blog.csdn.net/s10461/article/details/53941091
 *  */
public class Test006_Generic {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        // 泛型类
        Generic<Integer> integerGeneric = new Generic<>(123);
        Generic<String> stringGeneric = new Generic<>("Key_value");
        System.out.println("泛型测试Generic<Integer>，key is " + integerGeneric.getKey());
        System.out.println("泛型测试Generic<String>，key is " + stringGeneric.getKey());
        // 泛型通配符
        Generic<Integer> g1 = new Generic<>(10);
        Generic<Number> g2 = new Generic<>(10.5);
        test(g2);
        // test(g1); // Generic<Integer> 不是 Generic<Number>的子类，二者没有关系，若要达到泛型子类的效果，需使用通配符?
        test1(g2);
        test1(g1); // 使用泛型通配符实现泛型继承
        Person p = genericMethod(Person.class);
        System.out.println(Person.class.getName());
        System.out.println(p.getName()); // Jack
    }

    public static void test(Generic<Number> g) {
        System.out.println("test generic key: " + g.getKey());
    }
    public static void test1(Generic<? extends Number> g) {
        System.out.println("test1 generic key: " + g.getKey());
    }
    /**
     * 泛型方法的基本介绍
     * @param tClass 传入的泛型实参
     * @return T 返回值为T类型
     * 说明：
     *     1）public 与 返回值中间<T>非常重要，可以理解为声明此方法为泛型方法。
     *     2）只有声明了<T>的方法才是泛型方法，泛型类中的使用了泛型的成员方法并不是泛型方法。
     *     3）<T>表明该方法将使用泛型类型T，此时才可以在方法中使用泛型类型T。
     *     4）与泛型类的定义一样，此处T可以随便写为任意标识，常见的如T、E、K、V等形式的参数常用于表示泛型。
     */
    public static <T> T genericMethod(Class<T> tClass) throws InstantiationException,
            IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        // T instance = (T) tClass.newInstance();
        T instance = tClass.getConstructor().newInstance();
        return instance;
    }

    /*
     * 泛型数组
     * 可以声明带泛型的数组引用，但不可创建带泛型的数组对象
     * */
    public static Generic<Integer>[] getArr() {
        // return new Generic<Integer>[5]; // 报错，new创建数组时，数组元素的类型不能带泛型，但是声明可以带泛型，比如方法返回值
        return new Generic[5];
    }

}

// 泛型类
// 泛型方法和泛型类，泛型参数都可用于局部变量类型，但是不能用new、instanceof作用于泛型参数
class Generic<T> {
    private T key;
    public Generic(T key) {
        T t = (T)new Object();
        this.key = key;
    }
    public T getKey() {
        return key;
    }
}

// 泛型接口
interface Generator<T> {
    public T next();
}

class FruitGenerator<T> implements Generator<T> {

    @Override
    public T next() {
        return null;
    }
}

class CarGenerator implements Generator<Number> {

    @Override
    public Number next() {
        return 10.5;
    }
}
